package net.entelijan.cobean.bind.impl.remove;

import java.util.ArrayList;
import java.util.List;

import net.entelijan.cobean.bind.impl.BoundPropBinding;
import net.entelijan.cobean.bind.impl.TestUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Assert;
import org.junit.Test;

public class RebindingTestcase {

    private static Log log = LogFactory.getLog(RebindingTestcase.class);

    @Test
    public void testBindingSimpleBean() {
        BoundPropBinding binding = new BoundPropBinding();
        binding.setCompProperty("value");
        binding.setModelPath("strVal");
        SimpleBean m1 = new SimpleBean("start");
        InvisibleCobean cobean = new InvisibleCobean();
        log.debug("---------- before m1 = binding.bind(m1, cobean); -----------------------");
        m1 = binding.bind(m1, cobean);
        log.debug("---------- after m1 = binding.bind(m1, cobean); -----------------------");
        pause();
        Assert.assertEquals("start", cobean.getValue());
        log.debug("---------- before m1.setStrVal(\"hallo\"); -----------------------");
        m1.setStrVal("hallo");
        log.debug("---------- after m1.setStrVal(\"hallo\"); -----------------------");
        pause();
        Assert.assertEquals("hallo", cobean.getValue());
    }

    @Test
    public void testBindValue02() {
        InvisibleSingleSelectionComponentBean cobean = new InvisibleSingleSelectionComponentBean();
        ModelBean m = new ModelBean();
        List<SimpleBean> beans = createSimpleBeans("A", "B", "C");
        m.setBeans(beans);
        m.setSelectedBean(beans.get(2));

        BoundPropBinding binding = new BoundPropBinding();
        binding.setCompProperty("value");
        binding.setModelPath("beans");

        binding.bind(m, cobean);

        Assert.assertEquals("A", cobean.getValue().get(0).getStrVal());
        Assert.assertEquals("B", cobean.getValue().get(1).getStrVal());
        Assert.assertEquals("C", cobean.getValue().get(2).getStrVal());
    }

    @Test
    public void testBindValue01() {
        InvisibleSingleSelectionComponentBean cobean = new InvisibleSingleSelectionComponentBean();
        ModelBean m = new ModelBean();
        List<SimpleBean> bs1 = createSimpleBeans("A", "B", "C");
        m.setBeans(bs1);
        m.setSelectedBean(bs1.get(2));

        BoundPropBinding binding = new BoundPropBinding();
        binding.setCompProperty("value");
        binding.setModelPath("beans");

        m = binding.bind(m, cobean);

        Assert.assertEquals("A", cobean.getValue().get(0).getStrVal());
        Assert.assertEquals("B", cobean.getValue().get(1).getStrVal());
        Assert.assertEquals("C", cobean.getValue().get(2).getStrVal());
        
        List<SimpleBean> bs2 = createSimpleBeans("X", "Y", "Z");
        m.setBeans(bs2);
        
        Assert.assertEquals("X", cobean.getValue().get(0).getStrVal());
        Assert.assertEquals("Y", cobean.getValue().get(1).getStrVal());
        Assert.assertEquals("Z", cobean.getValue().get(2).getStrVal());
    }

    @Test
    public void testBindValue00() {
        InvisibleSingleSelectionComponentBean cobean = new InvisibleSingleSelectionComponentBean();
        ModelBean m = new ModelBean();
        List<SimpleBean> beans = createSimpleBeans("A", "B", "C");
    
        BoundPropBinding binding = new BoundPropBinding();
        binding.setCompProperty("value");
        binding.setModelPath("beans");
    
        m = binding.bind(m, cobean);
        m.setBeans(beans);
        m.setSelectedBean(beans.get(2));
    
        Assert.assertEquals("A", cobean.getValue().get(0).getStrVal());
        Assert.assertEquals("B", cobean.getValue().get(1).getStrVal());
        Assert.assertEquals("C", cobean.getValue().get(2).getStrVal());
    }

    @Test
    public void testBindSelectedValue00() {
        InvisibleSingleSelectionComponentBean cobean = new InvisibleSingleSelectionComponentBean();
        ModelBean m = new ModelBean();
        List<SimpleBean> beans = createSimpleBeans("A", "B", "C");
        m.setBeans(beans);
        m.setSelectedBean(beans.get(0));
    
        BoundPropBinding binding = new BoundPropBinding();
        binding.setCompProperty("selectedValue");
        binding.setModelPath("selectedBean");
    
        binding.bind(m, cobean);
    
        Assert.assertEquals(cobean.getSelectedValue().getStrVal(), "A");
    }

    @Test
    public void testBindSelectedValue01() {
        InvisibleSingleSelectionComponentBean cobean = new InvisibleSingleSelectionComponentBean();
        ModelBean m = new ModelBean();
        List<SimpleBean> beans = createSimpleBeans("A", "B", "C");
    
        BoundPropBinding binding = new BoundPropBinding();
        binding.setCompProperty("selectedValue");
        binding.setModelPath("selectedBean");
    
        m = binding.bind(m, cobean);
        m.setBeans(beans);
        m.setSelectedBean(beans.get(0));
    
        Assert.assertEquals("A", cobean.getSelectedValue().getStrVal());
    }

    @Test
    public void testBindBothProps00() {
        InvisibleSingleSelectionComponentBean cobean = new InvisibleSingleSelectionComponentBean();
        ModelBean m = new ModelBean();
        List<SimpleBean> beans = createSimpleBeans("A", "B", "C");
        m.setBeans(beans);
        m.setSelectedBean(beans.get(2));
        log.debug("----------(0)------------------------------------------");
        {
            BoundPropBinding binding = new BoundPropBinding();
            binding.setCompProperty("value");
            binding.setModelPath("beans");

            log.debug("----------(0a)------------------------------------------");
            m = binding.bind(m, cobean);
            log.debug("----------(1)------------------------------------------");
        }
        Assert.assertEquals("A", cobean.getValue().get(0).getStrVal());
        Assert.assertEquals("B", cobean.getValue().get(1).getStrVal());
        Assert.assertEquals("C", cobean.getValue().get(2).getStrVal());
        {
            BoundPropBinding binding = new BoundPropBinding();
            log.debug("----------(1a)------------------------------------------");
            binding.setCompProperty("selectedValue");
            log.debug("----------(1b)------------------------------------------");
            binding.setModelPath("selectedBean");
            log.debug("----------(1c)------------------------------------------");

            m = binding.bind(m, cobean);
            log.debug("----------(2)------------------------------------------");
        }
        Assert.assertEquals("A", cobean.getValue().get(0).getStrVal());
        Assert.assertEquals("B", cobean.getValue().get(1).getStrVal());
        Assert.assertEquals("C", cobean.getValue().get(2).getStrVal());

        Assert.assertEquals("C", cobean.getSelectedValue().getStrVal());

        m.setSelectedBean(beans.get(1));
        log.debug("----------(3)------------------------------------------");
        Assert.assertEquals("B", cobean.getSelectedValue().getStrVal());
        log.debug("----------(4)------------------------------------------");
    }

    @Test
    public void testBindBothProps02() {
        InvisibleSingleSelectionComponentBean cobean = new InvisibleSingleSelectionComponentBean();
        ModelBean m = new ModelBean();
        List<SimpleBean> beans = createSimpleBeans("A", "B", "C");
        m.setBeans(beans);
        m.setSelectedBean(beans.get(2));

        {
            BoundPropBinding binding = new BoundPropBinding();
            binding.setCompProperty("selectedValue");
            binding.setModelPath("selectedBean");

            m = binding.bind(m, cobean);
        }
        Assert.assertEquals("C", cobean.getSelectedValue().getStrVal());

        {
            BoundPropBinding binding = new BoundPropBinding();
            binding.setCompProperty("value");
            binding.setModelPath("beans");

            m = binding.bind(m, cobean);
        }
        Assert.assertEquals("A", cobean.getValue().get(0).getStrVal());
        Assert.assertEquals("B", cobean.getValue().get(1).getStrVal());
        Assert.assertEquals("C", cobean.getValue().get(2).getStrVal());
        
        Assert.assertEquals("C", cobean.getSelectedValue().getStrVal());
        
        m.setSelectedBean(beans.get(1));
        Assert.assertEquals("B", cobean.getSelectedValue().getStrVal());
    }

    @Test
    public void testBindBothProps01() {
        InvisibleSingleSelectionComponentBean cobean = new InvisibleSingleSelectionComponentBean();
        ModelBean m = new ModelBean();
        List<SimpleBean> bs1 = createSimpleBeans("A", "B", "C");
        m.setBeans(bs1);
        m.setSelectedBean(bs1.get(2));

        {
            BoundPropBinding binding = new BoundPropBinding();
            binding.setCompProperty("value");
            binding.setModelPath("beans");

            m = binding.bind(m, cobean);
        }
        Assert.assertEquals("A", cobean.getValue().get(0).getStrVal());
        Assert.assertEquals("B", cobean.getValue().get(1).getStrVal());
        Assert.assertEquals("C", cobean.getValue().get(2).getStrVal());
        {
            BoundPropBinding binding = new BoundPropBinding();
            binding.setCompProperty("selectedValue");
            binding.setModelPath("selectedBean");

            m = binding.bind(m, cobean);
        }
        Assert.assertEquals("A", cobean.getValue().get(0).getStrVal());
        Assert.assertEquals("B", cobean.getValue().get(1).getStrVal());
        Assert.assertEquals("C", cobean.getValue().get(2).getStrVal());

        Assert.assertEquals("C", cobean.getSelectedValue().getStrVal());

        m.setSelectedBean(bs1.get(1));
        Assert.assertEquals("B", cobean.getSelectedValue().getStrVal());
        
        List<SimpleBean> bs2 = createSimpleBeans("X", "Y", "Z");
        m.setBeans(bs2);
//        m.setSelectedBean(bs2.get(2));
        
        Assert.assertEquals("X", cobean.getValue().get(0).getStrVal());
        Assert.assertEquals("Y", cobean.getValue().get(1).getStrVal());
        Assert.assertEquals("Z", cobean.getValue().get(2).getStrVal());

  //      Assert.assertEquals("Z", cobean.getSelectedValue().getStrVal());
    }
    
    @Test
    public void testRebinding() {
        BoundPropBinding binding = new BoundPropBinding();
        binding.setCompProperty("value");
        binding.setModelPath("strVal");
        SimpleBean m1 = new SimpleBean("start");
        InvisibleCobean cobean = new InvisibleCobean();
        log.debug("---------- before m1 = binding.bind(m1, cobean); -----------------------");
        m1 = binding.bind(m1, cobean);
        log.debug("---------- after m1 = binding.bind(m1, cobean); -----------------------");
        pause();
        Assert.assertEquals("start", cobean.getValue());
        
        m1.setStrVal("hallo");

        TestUtil.assertChangeListenerCount(1, m1);
        TestUtil.assertCobeanHasOneListener(cobean);

        Assert.assertEquals("hallo", cobean.getValue());

        SimpleBean m2 = new SimpleBean("stop");
        Assert.assertEquals("stop", m2.getStrVal());
        log.debug("------- before binding.bind(m2, cobean --------------");
        m2 = binding.bind(m2, cobean);
        log.debug("------- after binding.bind(m2, cobean --------------");
        pause();
        Assert.assertEquals("stop", m2.getStrVal());
        Assert.assertEquals("stop", cobean.getValue());

        TestUtil.assertChangeListenerCount(1, m2);
        TestUtil.assertChangeListenerCount(0, m1);
        pause();
        TestUtil.assertCobeanHasOneListener(cobean);
        Assert.assertEquals("stop", m2.getStrVal());

        m2.setStrVal("A");
        pause();
        Assert.assertEquals("A", cobean.getValue());

        cobean.setValue("B");
        pause();
        Assert.assertEquals("B", m2.getStrVal());
        Assert.assertEquals("hallo", m1.getStrVal());
    }

    private synchronized void pause() {
        try {
            this.wait(300);
        } catch (InterruptedException e) {
            // Can be ignored
        }
    }

    private List<SimpleBean> createSimpleBeans(String... strVals) {
        ArrayList<SimpleBean> re = new ArrayList<SimpleBean>();
        for (String strVal : strVals) {
            re.add(new SimpleBean(strVal));
        }
        return re;
    }

}
